package cn.graydove.bot.service.impl;

import cn.graydove.bot.exception.FileErrorException;
import cn.graydove.bot.model.entity.Image;
import cn.graydove.bot.repository.ImageRepository;
import cn.graydove.bot.service.ImageService;
import cn.graydove.bot.support.ApiProperties;
import cn.graydove.bot.support.BotProperties;
import cn.graydove.bot.support.Oss;
import cn.graydove.bot.utils.UrlUtils;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.PutObjectRequest;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.CopyOnWriteArrayList;

@Service
public class ImageServiceImpl implements ImageService {

    private ImageRepository imageRepository;

    private BotProperties botProperties;

    private final List<Image> imageCache = new CopyOnWriteArrayList<>();

    private Random random = new Random();

    public ImageServiceImpl(ImageRepository imageRepository, BotProperties botProperties) {
        this.imageRepository = imageRepository;
        this.botProperties = botProperties;
    }

    @Override
    @Transactional(rollbackFor = {Exception.class})
    public Image upload(String uploaderNickname, Long uploader, Long uploadGroup, String imgUrl, String filename) throws IOException {

            URL url = new URL(imgUrl);
            HttpURLConnection conn = (HttpURLConnection)url.openConnection();
            conn.setReadTimeout(2 * 1000);
            conn.setRequestMethod("GET");
            InputStream is = conn.getInputStream();

            byte[] byteArray = is.readAllBytes();

            if (byteArray.length > 2 * 1024 * 1024) {
                throw new FileErrorException("图片过大，暂时仅支持2M以下的图片");
            }

            filename = UUID.nameUUIDFromBytes(byteArray) + filename.substring(filename.lastIndexOf("."));

            Image image = new Image(uploaderNickname, uploader, uploadGroup, filename);
            Image save = imageRepository.save(image);

            upload(byteArray, filename);

            flushCache();
            return save;
    }

    private void flushCache() {
        synchronized (imageCache) {
            imageCache.clear();
            imageCache.addAll(imageRepository.findAll());
        }
    }

    @Override
    public List<Image> getImages() {
        if (imageCache.isEmpty()) {
            imageCache.addAll(imageRepository.findAll());
        }
        return new ArrayList<>(imageCache);
    }

    @Override
    public Image getRandomOne() {
        List<Image> images = getImages();
        if (images == null || images.isEmpty()) {
            return null;
        }
        return images.get(random.nextInt(images.size()));
    }

    @Override
    public Image findById(int id) {
        return imageRepository.findById(id).orElse(null);
    }

    @Override
    public Image findByImageName(String image) {
        return imageRepository.findByFilename(image);
    }

    @Override
    public void deleteById(int id) {
        imageRepository.deleteById(id);

        flushCache();
    }

    private void upload(byte[] data, String filename) {
        ApiProperties api = botProperties.getApi();
        Oss oss = api.getOss();
        String endpoint = oss.getEndPoint();

        String accessKeyId = api.getAccessKeyId();
        String accessKeySecret = api.getAccessSecret();

        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

        PutObjectRequest putObjectRequest = new PutObjectRequest(oss.getBucketName(), getUri(filename), new ByteArrayInputStream(data));

        // 如果需要上传时设置存储类型与访问权限，请参考以下示例代码。
        // ObjectMetadata metadata = new ObjectMetadata();
        // metadata.setHeader(OSSHeaders.OSS_STORAGE_CLASS, StorageClass.Standard.toString());
        // metadata.setObjectAcl(CannedAccessControlList.Private);
        // putObjectRequest.setMetadata(metadata);

        // 上传字符串。
        ossClient.putObject(putObjectRequest);

        // 关闭OSSClient。
        ossClient.shutdown();
    }

    public String getUri(String filename) {
        String dir = botProperties.getApi().getOss().getSavedPath();
        if (!dir.endsWith("/")) {
            dir += "/";
        }

        return dir + filename;
    }

    public String getVisitUrl(String filename) {
        String uri = getUri(filename);
        if (uri.startsWith("/")) {
            uri = uri.substring(1);
        }
        String visitUrl = botProperties.getApi().getOss().getVisitUrl();
        if (visitUrl == null || visitUrl.length() < 2) {
            throw new RuntimeException("无效的visitUrl");
        }
        visitUrl = UrlUtils.urlFormat(visitUrl);
        if (!visitUrl.endsWith("/")) {
            visitUrl += "/";
        }
        return visitUrl + uri;
    }
}
